﻿namespace Mercury.ParticleEngine
{
    using System;
    using System.Runtime.Serialization;
    using Xunit;
    using FluentAssertions;
    using Xunit.Extensions;

    // ReSharper disable InconsistentNaming

    public class RadianAngleTests
    {
        public class DeserializationConstructor
        {
            [Fact]
            [Trait("Type", "RadianAngle")]
            public void WhenGivenNullSerializationInfo_ThrowsArgumentNullException()
            {
                Action invocation = () => new RadianAngle(null, new StreamingContext());

                invocation.ShouldThrow<ArgumentNullException>();
            }

            [Fact]
            [Trait("Type", "RadianAngle")]
            public void WhenGivenSerializationInfo_ReturnsInitializedRadianAngle()
            {
                var serializationInfo = new SerializationInfo(typeof(RadianAngle), new FormatterConverter());

                serializationInfo.AddValue("value", 1f);

                var result = new RadianAngle(serializationInfo, new StreamingContext());

                var expected = new RadianAngle(1f);

                result.Should().Be(expected);
            }
        }

        public class EqualsMethod
        {
            [Fact]
            [Trait("Type", "RadianAngle")]
            public void WhenGivenNull_ReturnsFalse()
            {
                var angle = new RadianAngle(1f);

                angle.Equals(null).Should().BeFalse();
            }

            [Fact]
            [Trait("Type", "RadianAngle")]
            public void WhenGivenObjectOfAnotherType_ReturnsFalse()
            {
                var angle = new RadianAngle(1f);

// ReSharper disable SuspiciousTypeConversion.Global
                angle.Equals(DateTime.Now).Should().BeFalse();
// ReSharper restore SuspiciousTypeConversion.Global
            }

            [Fact]
            [Trait("Type", "RadianAngle")]
            public void WhenGivenEqualValueAsObject_ReturnsTrue()
            {
                var angle1 = new RadianAngle(1f);
                var angle2 = new RadianAngle(1f);

                angle1.Equals(angle2 as Object).Should().BeTrue();
            }

            [Fact]
            [Trait("Type", "RadianAngle")]
            public void WhenGivenDifferentValueAsObject_ReturnsFalse()
            {
                var angle1 = new RadianAngle(1f);
                var angle2 = new RadianAngle(2f);

                angle1.Equals(angle2 as Object).Should().BeFalse();
            }

            [Fact]
            [Trait("Type", "RadianAngle")]
            public void WhenGivenEqualValue_ReturnsTrue()
            {
                var angle1 = new RadianAngle(1f);
                var angle2 = new RadianAngle(1f);

                angle1.Equals(angle2).Should().BeTrue();
            }

            [Fact]
            [Trait("Type", "RadianAngle")]
            public void WhenGivenDifferentValue_ReturnsFalse()
            {
                var angle1 = new RadianAngle(1f);
                var angle2 = new RadianAngle(2f);

                angle1.Equals(angle2).Should().BeFalse();
            }
        }

        public class GetHashCodeMethod
        {
            [Fact]
            [Trait("Type", "RadianAngle")]
            public void WhenObjectsAreDifferent_YieldsDifferentHashCodes()
            {
                var x = new RadianAngle(0f);
                var y = new RadianAngle(1f);

                x.GetHashCode().Should().NotBe(y.GetHashCode());
            }

            [Fact]
            [Trait("Type", "RadianAngle")]
            public void WhenObjectsAreEqual_YieldsIdenticalHashCodes()
            {
                var x = new RadianAngle(1f);
                var y = new RadianAngle(1f);

                x.GetHashCode().Should().Be(y.GetHashCode());
            }
        }

        public class ToStringMethod
        {
            [Theory]
            [Trait("Type", "RadianAngle")]
            [InlineData(0f, "0.0000")]
            [InlineData(1f, "1.0000")]
            [InlineData(3.14159f, "3.1416")]
            public void ReturnsCorrectValue(Single value, String expected)
            {
                var angle = new RadianAngle(value);

// ReSharper disable SpecifyACultureInStringConversionExplicitly
                angle.ToString().Should().Be(expected);
// ReSharper restore SpecifyACultureInStringConversionExplicitly
            }
        }

        public class CompareToMethod
        {
            [Fact]
            [Trait("Type", "RadianAngle")]
            public void WhenValueIsSmaller_ReturnsPositiveValue()
            {
                var angle1 = new RadianAngle(1f);
                var angle2 = new RadianAngle(0f);

                angle1.CompareTo(angle2).Should().BeGreaterThan(0);
            }

            [Fact]
            [Trait("Type", "RadianAngle")]
            public void WhenValueIsEqual_ReturnsZero()
            {
                var angle1 = new RadianAngle(1f);
                var angle2 = new RadianAngle(1f);

                angle1.CompareTo(angle2).Should().Be(0);
            }

            [Fact]
            [Trait("Type", "RadianAngle")]
            public void WhenValueIsLarger_ReturnsNegativeValue()
            {
                var angle1 = new RadianAngle(1f);
                var angle2 = new RadianAngle(2f);

                angle1.CompareTo(angle2).Should().BeLessThan(0);
            }
        }

        public class GetObjectDataMethod
        {

            [Fact]
            [Trait("Type", "RadianAngle")]
            public void WhenGivenSerializationInfo_PopulatesIt()
            {
                ISerializable instance = new RadianAngle(1f);

                var serializationInfo = new SerializationInfo(typeof(RadianAngle), new FormatterConverter());

                instance.GetObjectData(serializationInfo, new StreamingContext());

                serializationInfo.GetSingle("value").Should<Single>().Be(1f);
            }
        }
    }

    // ReSharper restore InconsistentNaming
}